Flutter 渲染流水线
对 Flutter 渲染机制,在网络上已经有诸多优秀资源,文本是我对这些优秀文章学习后的笔记。本文中的内容对这些文章多有引用,在此统一声明。相关好文章如下:
- 《Flutter渲染流程(一)-UI线程工作 | Chen's Notes》
- 《Flutter 核心渲染流程分析 [完结篇] - 掘金》
- 《深入浅出 Flutter Framework 之 BuildOwner - 掘金》
Step1:以 setState 触发帧调度
开发者调用 setState
触发状态更新:
// State
@protected
void setState(VoidCallback fn) {
// ...
final Object? result = fn() as dynamic;
// ...
_element!.markNeedsBuild();
}
调用 element 标脏:
// Element
void markNeedsBuild() {
// ...
// 已经标过的不会重复标
if (dirty) return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
来到 BuildOwner:
// BuildOwner
void scheduleBuildFor(Element element) {
//...
// 如果已经在列表中,直接返回
if (element._inDirtyList) {
// ...
// 用于标记在构建过程中是否有更多的元素变为"dirty"(需要重新构建),从而需要重新对`_dirtyElements`进行排序。
_dirtyElementsNeedsResorting = true;
return;
}
// onBuildScheduled 方法非常关键
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!();
}
// 添加到脏的列表中
_dirtyElements.add(element);
element._inDirtyList = true;
// ...
}
WidgetsBinding 关联了 onBuildScheduled,当 onBuildScheduled 调用时,实际调用的是 WidgetsBinding 的 _handleBuildScheduled
。
void _handleBuildScheduled() {
ensureVisualUpdate();
}
ensureVisualUpdate 将会调度一个新的帧:
// SchedulerBinding
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
// SchedulerBinding
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
ensureFrameCallbacksRegistered();
window.scheduleFrame();
_hasScheduledFrame = true;
}
接下来从 Flutter Framework 中来到 Flutter Engine:
// window.dart
void scheduleFrame() => platformDispatcher.scheduleFrame();
// platformDispatcher
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
来到 platform_configuration.cc 的 ScheduleFrame:
void ScheduleFrame(Dart_NativeArguments args) {
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}
client 实际上是 RuntimeController:
// RuntimeController
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
调用到 Engine 的 ScheduleFrame:
// Engine
void ScheduleFrame() { ScheduleFrame(true); }
// Engine
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
StartAnimatorIfPossible();
animator_->RequestFrame(regenerate_layer_tree);
}
// Engine
void Engine::StartAnimatorIfPossible() {
if (activity_running_ && have_surface_) {
animator_->Start();
}
}
Step2:ASYNC 信号注册
其中,animator_
会注册 ASYNC 信号。
// Animator
void Animator::Start() {
if (!paused_) {
return;
}
paused_ = false;
RequestFrame();
}
// Animator
void Animator::RequestFrame(bool regenerate_layer_tree) {
//...
task_runners_.GetUITaskRunner()->PostTask(
[self = weak_factory_.GetWeakPtr(),
frame_request_number = frame_request_number_]() {
if (!self) {
return;
}
// 等待 ASYNC 信号
self->AwaitVSync();
});
frame_scheduled_ = true;
}
// Animator
void Animator::AwaitVSync() {
waiter_->AsyncWaitForVsync(
[self = weak_factory_.GetWeakPtr()](
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
// ASYNC 信号回来
if (self) {
if (self->CanReuseLastLayerTree()) {
self->DrawLastLayerTreemove(frame_timings_recorder);
} else {
// 开始新的一帧
self->BeginFramemove(frame_timings_recorder);
}
}
});
// ...
}
setState
调用window.scheduleFrame
window.scheduleFrame
注册 VSYNC 回调- VSYNC 到来,调用
window.cc
的BeginFrame
window.cc
的BeginFrame
会调用 DartSchedulerBinding
的_handleBeginFrame
和_handleDrawFrame
方法
Step3:BeginFrame 开启新的一帧
// Animator
void Animator::BeginFrame(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
// ...
{
uint64_t frame_number = frame_timings_recorder_->GetFrameNumber();
delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
}
}
// Shell
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
uint64_t frame_number) {
// ...
if (engine_) {
engine_->BeginFrame(frame_target_time, frame_number);
}
}
// Engine
void Engine::BeginFrameTimePoint frame_time, uint64_t frame_number {
TRACE_EVENT0("flutter", "Engine::BeginFrame");
runtime_controller_->BeginFrame(frame_time, frame_number);
}
// RuntimeController
bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
uint64_t frame_number) {
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
platform_configuration->BeginFrame(frame_time, frame_number);
return true;
}
return false;
}
// PlatformConfiguration
void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime,
uint64_t frame_number) {
// 调用 dart 中的 _window.onBeginFrame
std::shared_ptr<tonic::DartState> dart_state =
begin_frame_.dart_state().lock();
if (!dart_state) {
return;
}
tonic::DartState::Scope scope(dart_state);
// 刷新 microTasks
UIDartState::Current()->FlushMicrotasksNow();
// 调用 _drawFrame
tonic::LogIfErrorDartInvokeVoid(draw_frame_.Get());
}
在 PlatformConfiguration::BeginFrame 中,分别调用了两个 Dart 方法:
begin_frame_
:引擎中的 Dart 方法window.onBeginFrame
,最终 Framework 的 Dart 方法ScheduleBinding._handleBeginFrame
draw_frame_
:引擎中的 Dart 方法window.onDrawFrame
,最终 Framework 的 Dart 方法ScheduleBinding._handleDrawFrame
这两方法的绑定过程:
// hooks.dart
@pragma('vm:entry-point')
void _beginFrame(int microseconds, int frameNumber) {
PlatformDispatcher.instance._beginFrame(microseconds);
PlatformDispatcher.instance._updateFrameData(frameNumber);
}
// hooks.dart
@pragma('vm:entry-point')
void _drawFrame() {
PlatformDispatcher.instance._drawFrame();
}
// platform_dispatcher.dart
FrameCallback? get onBeginFrame => _onBeginFrame;
FrameCallback? _onBeginFrame;
Zone _onBeginFrameZone = Zone.root;
set onBeginFrame(FrameCallback? callback) {
_onBeginFrame = callback;
_onBeginFrameZone = Zone.current;
}
void _beginFrame(int microseconds) {
_invoke1<Duration>(
onBeginFrame,
_onBeginFrameZone,
Duration(microseconds: microseconds),
);
}
// platform_dispatcher.dart
VoidCallback? get onDrawFrame => _onDrawFrame;
VoidCallback? _onDrawFrame;
Zone _onDrawFrameZone = Zone.root;
set onDrawFrame(VoidCallback? callback) {
_onDrawFrame = callback;
_onDrawFrameZone = Zone.current;
}
// Called from the engine, via hooks.dart
void _drawFrame() {
_invoke(onDrawFrame, _onDrawFrameZone);
}
之后来到 Framework 侧:
// ScheduleBinding
@protected
void ensureFrameCallbacksRegistered() {
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
Step3-1:_handleBeginFrame
这一步处理临时性任务,比如动画的计算。对应的遍历执行 transientCallbacks 毁掉集合。
// ScheduleBinding
void _handleBeginFrame(Duration rawTimeStamp) {
// ...
handleBeginFrame(rawTimeStamp);
}
// ScheduleBinding
void handleBeginFrame(Duration? rawTimeStamp) {
//...
try {
// 执行基于 Ticker 的动画任务更新回调
_schedulerPhase = SchedulerPhase.transientCallbacks;
final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
_transientCallbacks = <int, _FrameCallbackEntry>{};
callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
if (!_removedIds.contains(id))
_invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
});
_removedIds.clear();
} finally {
// 状态流转:后续由 C++ 调度 microTasks
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
Step3-2:_handleDrawFrame
从代码看,这一步与上一步差不多,遍历执行 persistentCallbacks 集合。但这一步里面大有乾坤,Flutter Widget Tree 的 Build、Layout、Paint 都是在其中完成的。
// ScheduleBinding
void _handleDrawFrame() {
// ...
handleDrawFrame();
}
// ScheduleBinding
void handleDrawFrame() {
try {
// PERSISTENT FRAME CALLBACKS
// 这些回调是绘制一帧所必须的,如 build、layout、paint
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
// POST-FRAME CALLBACKS
// PostFrameCallback 的调用时机
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.of(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
} finally {
// 一帧调度完成,进入空闲状态
_schedulerPhase = SchedulerPhase.idle;
}
}
在 Framework 中搜索调用 addPersistentFrameCallback 的地方有很多,但其中有一位特别的重量级选手——RendererBinding,Flutter Widget Tree 的 Build、Layout、Paint 都是在其中完成的:
// ScheduleBinding
void addPersistentFrameCallback(FrameCallback callback) {
_persistentCallbacks.add(callback);
}
// RendererBinding
@override
void initInstances() {
super.initInstances();
// ...
addPersistentFrameCallback(_handlePersistentFrameCallback);
// ...
}
// RendererBinding
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
_scheduleMouseTrackerUpdate();
}
Step4:组件树构建
drawFrame 方法,是组件树的构建方法,将会触发 Build、Layout、Paint。需要注意的是,Bindings 采用 mixin 机制,drawFrame 将由多个 Bindings 共同协作完成:
// WidgetsBinding
@override
void drawFrame() {
// ...
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!);
super.drawFrame();
buildOwner!.finalizeTree();
}
// RendererBinding
@protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
_firstFrameSent = true;
}
}
整体构建顺序为:
- build:buildScope
- 布局:flushLayout
- Layer 合成:flushCompositingBits
- 绘制:flushPaint
- 清理:finalizeTree
一共 5 步,下面分别介绍。
Step4-1:Build 阶段
在 Step 中,我们通过 setState 对 element 标脏。在 buildOwner!.buildScope
中会对他们进行统一处理,按照深度排序的顺序 rebuild。所谓深度排序,先让父组件 rebuild,再让子组件 rebuild,防止子组件重复构建。核心代码:
// BuildOwner
void buildScope(Element context, [ VoidCallback? callback ]) {
if (callback == null && _dirtyElements.isEmpty)
return;
try {
if (callback != null) {
callback();
}
_dirtyElements.sort(Element._sort);
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
final Element element = _dirtyElements[index];
try {
element.rebuild();
} catch (e, stack) {/*...*/ }
index += 1;
}
} finally {
for (final Element element in _dirtyElements) {
element._inDirtyList = false;
}
_dirtyElements.clear();
}
}
// Element
void rebuild() {
if (_lifecycleState != _ElementLifecycle.active || !_dirty)
return;
// 抽象方法,由具体 Element 实现
performRebuild();
}
// ComponentElement
void performRebuild() {
Widget? built;
try {
built = build();
} catch (e, stack) { /*...*/}
finally {/*...*/}
try {
_child = updateChild(_child, built, slot);
} catch (e, stack) {
// ...
_child = updateChild(null, built, slot);
}
}
Step4-2:Layout 阶段
对所有标记为 dirty 的 Render Object 重新计算布局。
// PipelineOwner
void flushLayout() {
try {
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = <RenderObject>[];
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
if (node._needsLayout && node.owner == this)
node._layoutWithoutResize();
}
}
} finally {}
}
Step4-3:刷新合成位
// PipelineOwner
void flushCompositingBits() {
_nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
if (node._needsCompositingBitsUpdate && node.owner == this)
node._updateCompositingBits();
}
_nodesNeedingCompositingBitsUpdate.clear();
}
Step4-4:绘制
根据 Render Object 生成 Display LIst。这一步会调用 Render Object 的 paint 方法,生成 Layer。
// PipelineOwner
void flushPaint() {
try {
final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
_nodesNeedingPaint = <RenderObject>[];
// Sort the dirty nodes in reverse order (deepest first).
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
assert(node._layerHandle.layer != null);
if (node._needsPaint && node.owner == this) {
if (node._layerHandle.layer!.attached) {
PaintingContext.repaintCompositedChild(node);
} else {
node._skippedPaintingOnLayer();
}
}
}
} finally {}
}
// PaintingContext
// Render Object 重绘
static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) {
assert(child._needsPaint);
_repaintCompositedChild(
child,
debugAlsoPaintedParent: debugAlsoPaintedParent,
);
}
// PaintingContext
static void _repaintCompositedChild(
RenderObject child, {
bool debugAlsoPaintedParent = false,
PaintingContext? childContext,
}) {
OffsetLayer? childLayer = child._layerHandle.layer as OffsetLayer?;
if (childLayer == null) {
// Not using the `layer` setter because the setter asserts that we not
// replace the layer for repaint boundaries. That assertion does not
// apply here because this is exactly the place designed to create a
// layer for repaint boundaries.
final OffsetLayer layer = OffsetLayer();
child._layerHandle.layer = childLayer = layer;
} else {
childLayer.removeAllChildren();
}
childContext ??= PaintingContext(childLayer, child.paintBounds);
child._paintWithContext(childContext, Offset.zero);
// Double-check that the paint method did not replace the layer (the first
// check is done in the [layer] setter itself).
childContext.stopRecordingIfNeeded();
}
// RenderObject
void _paintWithContext(PaintingContext context, Offset offset) {
// If we still need layout, then that means that we were skipped in the
// layout phase and therefore don't need painting. We might not know that
// yet (that is, our layer might not have been detached yet), because the
// same node that skipped us in layout is above us in the tree (obviously)
// and therefore may not have had a chance to paint yet (since the tree
// paints in reverse order). In particular this will happen if they have
// a different layer, because there's a repaint boundary between us.
if (_needsLayout)
return;
_needsPaint = false;
try {
paint(context, offset);
} catch (e, stack) {
_debugReportException('paint', e, stack);
}
}
Step5:帧合成
绘制完成后,继续 RendererBinding.drawFrame 中的流程,接下来该帧合成:
// RenderView
void compositeFrame() {
try {
// 将 Layer 转换为 Scene
// 在 Dart 和 C++ 层都创建对应的 Builder 和 Scene
final ui.SceneBuilder builder = ui.SceneBuilder();
final ui.Scene scene = layer!.buildScene(builder);
// 将 Scene 发送给 GPU 线程
_window.render(scene);
scene.dispose();
} finally {}
}
Step6:提交 GPU 线程
// window.dart(Framework)
void render(Scene scene) => _render(scene, this);
void _render(Scene scene, FlutterView view) native 'PlatformConfiguration_render';
// PlatformConfiguration(Engine)
void Render(Dart_NativeArguments args) {
UIDartState::ThrowIfUIOperationsProhibited();
Dart_Handle exception = nullptr;
Scene* scene =
tonic::DartConverter<Scene*>::FromArguments(args, 1, exception);
UIDartState::Current()->platform_configuration()->client()->Render(scene);
}
// Engine.cc
void Engine::RenderLayerTree> layer_tree {
if (!layer_tree) {
return;
}
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||
layer_tree->device_pixel_ratio() <= 0.0f) {
return;
}
animator_->Rendermove(layer_tree);
}
// animator.cc
void Animator::RenderLayerTree> layer_tree {
// Commit the pending continuation.
bool result = producer_continuation_.Completemove(layer_tree);
// shell
delegate_.OnAnimatorDraw(layer_tree_pipeline_,
std::move(frame_timings_recorder_));
}
// shell.cc
void Shell::OnAnimatorDraw(
std::shared_ptr<Pipeline<flutter::LayerTree>> pipeline,
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
auto discard_callback = [this]LayerTree& tree {
std::scoped_lock<std::mutex> lock(resize_mutex_);
return !expected_frame_size_.isEmpty() &&
tree.frame_size() != expected_frame_size_;
};
// 切换到 GPU 线程
task_runners_.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
[&waiting_for_first_frame = waiting_for_first_frame_,
&waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
rasterizer = rasterizer_->GetWeakPtr(),
weak_pipeline = std::weak_ptr<Pipeline<LayerTree>>(pipeline),
discard_callback = std::move(discard_callback),
frame_timings_recorder = std::move(frame_timings_recorder)]() mutable {
if (rasterizer) {
// 线程锁
std::shared_ptr<Pipeline<LayerTree>> pipeline = weak_pipeline.lock();
if (pipeline) {
// GPU 绘制
rasterizer->Drawmove(frame_timings_recorder,
std::move(pipeline), std::move(discard_callback));
}
if (waiting_for_first_frame.load()) {
waiting_for_first_frame.store(false);
waiting_for_first_frame_condition.notify_all();
}
}
}));
}
Step7 rasterizer 绘制
// rasterizer.cc
RasterStatus Rasterizer::Draw(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
std::shared_ptr<Pipeline<flutter::LayerTree>> pipeline,
LayerTreeDiscardCallback discard_callback) {
// 如果开启了线程合并,这一步已经完成了
if (raster_thread_merger_ &&
!raster_thread_merger_->IsOnRasterizingThread()) {
// we yield and let this frame be serviced on the right thread.
return RasterStatus::kYielded;
}
std::unique_ptr<FrameTimingsRecorder> resubmit_recorder =
frame_timings_recorder->CloneUntil(
FrameTimingsRecorder::State::kBuildEnd);
RasterStatus raster_status = RasterStatus::kFailed;
Pipeline<flutter::LayerTree>::Consumer consumer =
[&]unique_ptr<LayerTree> layer_tree {
if (discard_callback(*layer_tree.get())) {
raster_status = RasterStatus::kDiscarded;
} else {
// 绘制
raster_status =
DoDrawmove(frame_timings_recorder), std::move(layer_tree);
}
};
PipelineConsumeResult consume_result = pipeline->Consume(consumer);
//...
if (surface_ && external_view_embedder_) {
external_view_embedder_->EndFrame(should_resubmit_frame,
raster_thread_merger_);
}
return raster_status;
}
// rasterizer.cc
RasterStatus Rasterizer::DoDraw(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
std::unique_ptr<flutter::LayerTree> layer_tree) {
PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
persistent_cache->ResetStoredNewShaders();
// 向 OpenGL Surface 绘制
RasterStatus raster_status =
DrawToSurface(*frame_timings_recorder, *layer_tree);
//...
// TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
// Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
// for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
delegate_.OnFrameRasterized(frame_timings_recorder->GetRecordedTime());
// Pipeline pressure is applied from a couple of places:
// rasterizer: When there are more items as of the time of Consume.
// animator (via shell): Frame gets produces every vsync.
// Enqueing here is to account for the following scenario:
// T = 1
// - one item (A) in the pipeline
// - rasterizer starts (and merges the threads)
// - pipeline consume result says no items to process
// T = 2
// - animator produces (B) to the pipeline
// - applies pipeline pressure via platform thread.
// T = 3
// - rasterizes finished (and un-merges the threads)
// - |Draw| for B yields as its on the wrong thread.
// This enqueue ensures that we attempt to consume from the right
// thread one more time after un-merge.
if (raster_thread_merger_) {
if (raster_thread_merger_->DecrementLease() ==
fml::RasterThreadStatus::kUnmergedNow) {
return RasterStatus::kEnqueuePipeline;
}
}
return raster_status;
}
Step7-1 Surface 绘制
// Rasterizer::DrawToSurface
RasterStatus Rasterizer::DrawToSurface(
FrameTimingsRecorder& frame_timings_recorder,
flutter::LayerTree& layer_tree) {
RasterStatus raster_status;
if (surface_->AllowsDrawingWhenGpuDisabled()) {
raster_status = DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree);
} else {
delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
fml::SyncSwitch::Handlers()
.SetIfTrue([&] { raster_status = RasterStatus::kDiscarded; })
.SetIfFalse([&] {
raster_status =
DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree);
}));
}
return raster_status;
}
// Rasterizer::DrawToSurfaceUnsafe
RasterStatus Rasterizer::DrawToSurfaceUnsafe(
FrameTimingsRecorder& frame_timings_recorder,
flutter::LayerTree& layer_tree) {
SkCanvas* embedder_root_canvas = nullptr;
// Hybrid Composition 下,PlatformView 的帧绘制是从这里开始的
if (external_view_embedder_) {
external_view_embedder_->BeginFrame(
layer_tree.frame_size(), surface_->GetContext(),
layer_tree.device_pixel_ratio(), raster_thread_merger_);
embedder_root_canvas = external_view_embedder_->GetRootCanvas();
}
// On Android, the external view embedder deletes surfaces in `BeginFrame`.
//
// Deleting a surface also clears the GL context. Therefore, acquire the
// frame after calling `BeginFrame` as this operation resets the GL context.
auto frame = surface_->AcquireFrame(layer_tree.frame_size());
if (frame == nullptr) {
return RasterStatus::kFailed;
}
// If the external view embedder has specified an optional root surface, the
// root surface transformation is set by the embedder instead of
// having to apply it here.
SkMatrix root_surface_transformation =
embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation();
auto root_surface_canvas =
embedder_root_canvas ? embedder_root_canvas : frame->SkiaCanvas();
// 帧合成器
auto compositor_frame = compositor_context_->AcquireFrame(
surface_->GetContext(), // skia GrContext
root_surface_canvas, // root surface canvas
external_view_embedder_.get(), // external view embedder
root_surface_transformation, // root surface transformation
true, // instrumentation enabled
frame->framebuffer_info()
.supports_readback, // surface supports pixel reads
raster_thread_merger_ // thread merger
);
if (compositor_frame) {
compositor_context_->raster_cache().PrepareNewFrame();
// Disable partial repaint if external_view_embedder_ SubmitFrame is
// involved - ExternalViewEmbedder unconditionally clears the entire
// surface and also partial repaint with platform view present is something
// that still need to be figured out.
bool disable_partial_repaint =
external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged());
FrameDamage damage;
if (!disable_partial_repaint && frame->framebuffer_info().existing_damage) {
damage.SetPreviousLayerTree(last_layer_tree_.get());
damage.AddAdditonalDamage(*frame->framebuffer_info().existing_damage);
}
// 光栅化
RasterStatus raster_status =
compositor_frame->Raster(layer_tree, false, &damage);
if (raster_status == RasterStatus::kFailed ||
raster_status == RasterStatus::kSkipAndRetry) {
return raster_status;
}
SurfaceFrame::SubmitInfo submit_info;
submit_info.frame_damage = damage.GetFrameDamage();
submit_info.buffer_damage = damage.GetBufferDamage();
frame->set_submit_info(submit_info);
// 上屏!
if (external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
FML_DCHECK(!frame->IsSubmitted());
external_view_embedder_->SubmitFrame(surface_->GetContext(),
std::move(frame));
} else {
frame->Submit();
}
compositor_context_->raster_cache().CleanupAfterFrame();
frame_timings_recorder.RecordRasterEnd(
&compositor_context_->raster_cache());
FireNextFrameCallbackIfPresent();
if (surface_->GetContext()) {
TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup");
surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
}
return raster_status;
}
return RasterStatus::kFailed;
}
在上屏前,有一个很重要的步骤 compositor_frame->Raster
光栅化。
Step7-2 光栅化
// RasterStatus CompositorContext::ScopedFrame
RasterStatus CompositorContext::ScopedFrame::Raster(
flutter::LayerTree& layer_tree,
bool ignore_raster_cache,
FrameDamage* frame_damage) {
std::optional<SkRect> clip_rect =
frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;
bool root_needs_readback = layer_tree.Preroll(
*this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
bool needs_save_layer = root_needs_readback && !surface_supports_readback();
PostPrerollResult post_preroll_result = PostPrerollResult::kSuccess;
if (view_embedder_ && raster_thread_merger_) {
post_preroll_result =
view_embedder_->PostPrerollAction(raster_thread_merger_);
}
if (post_preroll_result == PostPrerollResult::kResubmitFrame) {
return RasterStatus::kResubmit;
}
if (post_preroll_result == PostPrerollResult::kSkipAndRetryFrame) {
return RasterStatus::kSkipAndRetry;
}
SkAutoCanvasRestore restore(canvas(), clip_rect.has_value());
// Clearing canvas after preroll reduces one render target switch when preroll
// paints some raster cache.
// ...
// 遍历 LayerTree,光栅化
layer_tree.Paint(*this, ignore_raster_cache);
if (canvas() && needs_save_layer) {
canvas()->restore();
}
return RasterStatus::kSuccess;
}
其中,在有 Hybrid Composition 平台视图的场景下,还有两步:
layer_tree.Preroll
view_embedder_->PostPrerollAction
总结
至此 Flutter 的一帧绘制完成。
Flutter 渲染流水线梳理完毕。
本文作者:Maeiee
本文链接:Flutter 渲染流水线
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!